package Euclid;

import java.math.*;

public class FloatVarType extends VarType {
	public BigDecimal val;
	
	public int type = TYPE_FLOAT;
	
	private MathContext mc = MathContext.DECIMAL32;
	
	public FloatVarType(BigDecimal v) { val = v; formula = v.toString(); };
	public FloatVarType(BigDecimal v, String f) { val = v; formula = f; }
	public FloatVarType(BigInteger v, String f) { val = new BigDecimal(v); formula = f; }
	public FloatVarType(String v) { val = new BigDecimal(v); formula = v; }
	
	public VarType add(VarType o) {
		if (o instanceof IntVarType)
			return new FloatVarType(val.add(new BigDecimal(((IntVarType)o).val), mc),
					formula + " + " + o.formula);
		else if (o instanceof FloatVarType)
			return new FloatVarType(val.add(((FloatVarType)o).val, mc),
					formula + " + " + o.formula);
		else if (o instanceof SymbVarType)
			return add(((SymbVarType)o).val);
		else if (o instanceof ErrorVarType)
			return o;
		else
			return new ErrorVarType("Operation $+$ unsupported on type " + getClass());
	}
	
	public VarType subtract(VarType o) {
		if (o instanceof IntVarType)
			return new FloatVarType(val.subtract(new BigDecimal(((IntVarType)o).val), mc),
					formula + " - " + o.formula);
		else if (o instanceof FloatVarType)
			return new FloatVarType(val.subtract(((FloatVarType)o).val, mc),
					formula + " - " + o.formula);
		else if (o instanceof SymbVarType)
			return subtract(((SymbVarType)o).val);
		else if (o instanceof ErrorVarType)
			return o;
		else
			return new ErrorVarType("Operation $-$ unsupported on type " + getClass());
	}
	
	public VarType mult(VarType o) {
		if (o instanceof IntVarType)
			return new FloatVarType(val.multiply(new BigDecimal(((IntVarType)o).val), mc),
					formula + " \\times " + o.formula);
		else if (o instanceof FloatVarType)
			return new FloatVarType(val.multiply(((FloatVarType)o).val, mc),
					formula + " \\times " + o.formula);
		else if (o instanceof SymbVarType)
			return mult(((SymbVarType)o).val);
		else if (o instanceof ErrorVarType)
			return o;
		else
			return new ErrorVarType("Operation $\\times$ unsupported on type " + getClass());
	}
	
	public VarType div(VarType o) {
		if (o instanceof IntVarType)
			return new FloatVarType(val.divide(new BigDecimal(((IntVarType)o).val), mc),
					" \\frac{" + formula + "}{" + o.formula + "} ");
		else if (o instanceof FloatVarType)
			return new FloatVarType(val.divide(((FloatVarType)o).val, mc),
					" \\frac{" + formula + "}{" + o.formula + "} ");
		else if (o instanceof SymbVarType)
			return div(((SymbVarType)o).val);
		else if (o instanceof ErrorVarType)
			return o;
		else
			return new ErrorVarType("Operation $\\div$ unsupported on type " + getClass());
	}
	
	public VarType mod(VarType o) {
		return null;  // error
	}
	
	public VarType pow(VarType o) {
		if (o instanceof SymbVarType)
			return pow(((SymbVarType)o).val);
		else if (o instanceof IntVarType)
			return new FloatVarType(val.pow(((IntVarType)o).val.intValue(), mc),
					formula + "^{" + o.formula + "} ");
		else if (o instanceof ErrorVarType)
			return o;
		else
			return new ErrorVarType("Operation $x^y$ unsupported on type " + getClass());
	}
	
	public VarType factorial() {
		// TODO: truncate to integer?
		return new ErrorVarType("Operation $!$ unsupported on type " + getClass());
	}
	
	public VarType negate() {
		return new FloatVarType(val.negate(), "-" + formula);
	}
	
	public VarType not() {
		if (val.compareTo(BigDecimal.ZERO) == 0)
			return new IntVarType(BigInteger.ONE, " \\sim " + formula);
		else
			return new IntVarType(BigInteger.ZERO, " \\sim " + formula);
	}
	
	public String closeFormula() {
		return formula + " = " + val.toString();
	}
	
	public String toString() {
		return val.toString();
	}
}
